package org.senseframework.support.open.api.controller;
import org.senseframework.support.core.utils.DateUtils;
import org.senseframework.support.core.utils.DigestUtils;
import org.senseframework.support.core.utils.WebToolsUtils;
import org.senseframework.support.open.api.annotation.Encrypt;
import org.senseframework.support.open.api.controller.encrypt.ApplicationEncryptHandler;
import org.senseframework.support.open.api.controller.encrypt.EncryptException;
import org.senseframework.support.open.api.controller.encrypt.ExchangeKey;
import org.senseframework.support.open.api.exception.ApiException;
import org.senseframework.support.open.api.helper.IDataToMap;
import org.senseframework.support.open.api.helper.ResponseHelper;
import org.senseframework.support.open.api.service.ApiDefinition;
import org.senseframework.support.open.api.service.IApiService;
import org.senseframework.support.open.api.validate.ValidateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lanjian
 */
public class BasicController implements ApplicationContextAware {
    private ApplicationContext applicationContext=null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    private static Logger log = LoggerFactory.getLogger(ServiceController.class);

    private static final String system_time_service = "systemTime";

    protected Object handler(final String service,
                             final String version,
                             final String data,
                             final String appid,
                             final String salt,
                             final String sign,
                             final Long time,
                             final HttpServletRequest request,
                             final HttpServletResponse response,
                             final MultipartFile[] files,
                             final ApplicationEncryptHandler encrypt,
                             final String base,
                             final String token) {
        try {
            log.info("http method=========" + request.getMethod());
            log.info("service==========" + service);
            log.info("version==========" + version);
            log.info("data==========" + data);
            log.info("appid==========" + appid);
            log.info("sign==========" + sign);
            log.info("time==========" + time);
            log.info("base==========" + base);
            log.info("salt==========" + salt);
            log.info("token==========" + token);
            if (system_time_service.equals(service)) {
                return doSystemTime();
            }
            if (applicationContext == null) {
                throw new RuntimeException("applicationContext not be null");
            }
            final String sessionID = request.getSession().getId();
            final IApiService apiService = (IApiService) applicationContext.getBean(service + version);
            if (apiService == null) {
                throw new ApiException(ApiDefinition.NO_SERVICE_MESSAGE, ApiDefinition.FAIL_CODE);
            }

            //根据注解处理加密代码在这里
//            String method = request.getMethod().toUpperCase();
//            final ApplicationEncryptHandler encrypt=isEncrypt(apiService,method);
            return ResponseHelper.handler(new ResponseHelper.ResponseHandler() {
                public void log(Long total) {
                    log.info(service + version + "===exec===" + total + "=ms=");
                }

                public Map handler(String data) {
                    Map map = apiService.handler(service, version, data, WebToolsUtils.ip(request), files, sessionID, encrypt != null);
                    if (encrypt != null) {
                        //加密部分
                        final ExchangeKey exchangeKey = encrypt.findExchangeKey(token);
                        ResponseHelper.wrapper(map, encrypt, exchangeKey.getPassword());
                    }
                    return map;
                }

                public String data() throws Exception {
                    if (encrypt != null) {
                        //解密部分
                        final ExchangeKey exchangeKey = encrypt.findExchangeKey(token);
                        return encrypt.decode(exchangeKey.getPassword(), data);
                    }
                    return data;
                }

                public void validate() {
                    if (encrypt != null) {
                        String _sign = DigestUtils.md5(service + time + data + salt + version + appid);
                        //验证签名
                        if (!_sign.equals(sign)) {
                            log.info("_sign=" + _sign + ",orig=" + service + time + data + salt + version + appid);
                            throw new ApiException(ApiDefinition.FORBIDDEN_DEFAULT_MESSAGE, ApiDefinition.FORBIDDEN_ERROR_CODE);
                        }
                        //验证时间戳 15秒有效
                        Long now = DateUtils.nowDateTime();
                        if (now - time > 3600 * 1000) {
                            throw new ApiException(ApiDefinition.FORBIDDEN_DEFAULT_MESSAGE, ApiDefinition.FORBIDDEN_TIME_OUT_ERROR_CODE);
                        }

                    }
                }
            });
        } catch (ValidateException e) {
            log.info("ValidateException=====Msg=====" + e.getMessage() + "=====code======" + e.getCode(), e);
            return ResponseHelper.fail(e.getMessage(), e.getCode());
        } catch (ApiException e) {
            log.info("ApiException=====Msg=====" + e.getMessage() + "=====code======" + e.getCode(), e);
            return ResponseHelper.fail(e.getMessage(), e.getCode());
        } catch (EncryptException e) {
            log.info("ApiException=====Msg=====" + e.getMessage() + "=====code======" + e.getCode(), e);
            return ResponseHelper.fail(e.getMessage(), e.getCode());
        } catch (Exception ex) {
            log.info("===Exception===", ex);
            return ResponseHelper.fail();
        }
    }

    /**
     * 验证注解,判断服务是否需要加密处理
     * @param apiService
     * @param method
     * @return
     */
    public ApplicationEncryptHandler isEncrypt(IApiService apiService, String method) {
        //判断服务类是否需要加密处理
        if (apiService.getClass().isAnnotationPresent(Encrypt.class)) {
            try {
                RequestMethod rMethod = RequestMethod.valueOf(method);
                Encrypt encrypt1 = apiService.getClass().getAnnotation(Encrypt.class);
                List<RequestMethod> methodList = Arrays.asList(encrypt1.method());
                if (methodList.contains(rMethod)) {
                    return (ApplicationEncryptHandler) applicationContext.getBean(encrypt1.handler());
                }
            } catch (Exception ex) {
                log.info("ApiException=====Msg=====" + ex.getMessage(), ex);
            }
        }
        return null;
    }

    protected Object doSystemTime() {
        Map<String, Object> timeMap = new HashMap<String, Object>();
        timeMap.put("time", DateUtils.nowDateTime());
        return ResponseHelper.success(timeMap, new IDataToMap<Map<String, Object>>() {
            @Override
            public void dataToMap(Map<Object, Object> map, Map<String, Object> source) {
                map.put("time", source.get("time"));
            }
        });
    }
}
